package com.yw.service.Impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yw.ScriptInfo.domain.PythonScriptRequest;
import com.yw.ScriptInfo.domain.ScriptInfo;
import com.yw.ScriptInfo.dto.AddScriptDTO;
import com.yw.ScriptInfo.dto.QueryScriptDTO;
import com.yw.ScriptInfo.vo.OnclickNameVO;
import com.yw.ScriptInfo.vo.ScriptVO;
import com.yw.ScriptInfo.vo.TaskScriptVO;
import com.yw.ScriptInfo.vo.TaskScriptValueVO;
import com.yw.file.domain.FileBean;
import com.yw.interfaceManageInfo.domain.InterfaceManageInfo;
import com.yw.mapper.ScriptMapper;
import com.yw.piliangDTO.StatusDTO;
import com.yw.result.PageDTO;
import com.yw.result.R;
import com.yw.service.FileService;
import com.yw.service.ScriptService;
import com.yw.task.domain.Task;
import com.yw.utils.BeanConverter;
import com.yw.utils.PythonScriptDownloader;
import com.yw.utils.PythonScriptExecutor;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
public class ScriptServiceImpl extends ServiceImpl<ScriptMapper, ScriptInfo>
                               implements ScriptService {

    @Resource
    private ScriptMapper scriptMapper;
    @Resource
    private FileService fileService;
    private static final String UPLOAD_DIR = "D:/script/";

    @Override
    public Page<ScriptVO> pageScript(QueryScriptDTO queryScriptDTO) {
        LambdaQueryWrapper<ScriptInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(queryScriptDTO.getScriptName() != null,ScriptInfo::getScriptStatic,queryScriptDTO.getScriptName())
                .like(queryScriptDTO.getScriptName()!=null,ScriptInfo::getScriptName,queryScriptDTO.getScriptName());
        Page<ScriptInfo> page = new Page<>(queryScriptDTO.getPageNumber(), queryScriptDTO.getPageSize());
        Page<ScriptInfo> result = this.page(page, wrapper);
        Page<ScriptVO> scriptVOPage = new Page<>();
        scriptVOPage.setRecords(BeanConverter.convertList(page.getRecords(),ScriptVO.class));
        scriptVOPage.setCurrent(page.getCurrent());
        scriptVOPage.setTotal(page.getTotal());
        scriptVOPage.setSize(page.getSize());
        return scriptVOPage;
    }

    //批量发布或停用
    @Override
    public Boolean batch(StatusDTO statusDTO) {
        return scriptMapper.batch(statusDTO);
    }

    @Override
    public Boolean updateStatic(Integer id) {
        ScriptInfo scriptInfo = scriptMapper.selectById(id);
        switch (scriptInfo.getScriptStatic()){
            case 0, 2:
                scriptInfo.setScriptStatic(1);break;
            case 1:
                scriptInfo.setScriptStatic(2);break;
        }
        if(scriptMapper.updateById(scriptInfo) !=0){
            return true;
        }else {
            return false;
        }
    }

    //点击名字得到详情
    @Override
    public OnclickNameVO getScriptByName(Integer id) {
        ScriptInfo one = this.getById(id);
        OnclickNameVO onclickNameVO = new OnclickNameVO();
        onclickNameVO.setScriptName(one.getScriptName());
        onclickNameVO.setScriptDesc(one.getScriptDesc());
        onclickNameVO.setScriptType(one.getScriptType());
        onclickNameVO.setId(id);
        onclickNameVO.setLanguage(one.getLanguage());
        onclickNameVO.setFunction(one.getFunction());
        onclickNameVO.setClassName(one.getClassName());
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            onclickNameVO.setInParameter(objectMapper.readTree(one.getInParameter()));
            onclickNameVO.setOutParameter(objectMapper.readTree(one.getOutParameter()));
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return onclickNameVO;
    }

    @Override
    public Boolean addScript(AddScriptDTO addScriptDTO) {
        ScriptInfo scriptInfo = new ScriptInfo();
        scriptInfo.setScriptName(addScriptDTO.getScriptName());
        scriptInfo.setScriptType(addScriptDTO.getScriptType());
        scriptInfo.setScriptStatic(0);
        scriptInfo.setCreateTime(LocalDateTime.now());
        scriptInfo.setUpdateTime(LocalDateTime.now());
        scriptInfo.setScriptDesc(addScriptDTO.getScriptDesc());
        scriptInfo.setFunction(addScriptDTO.getFunction());
        scriptInfo.setLanguage(addScriptDTO.getLanguage());
        scriptInfo.setClassName(addScriptDTO.getClassName());
        scriptInfo.setInParameter(JSONUtil.toJsonStr(addScriptDTO.getInParameter()));
        scriptInfo.setOutParameter(JSONUtil.toJsonStr(addScriptDTO.getOutParameter()));
        scriptInfo.setFileId(addScriptDTO.getFileId());
        if (this.save(scriptInfo)){
            return true;
        }else {
            return false;
        }
    }

    @Override
    public R executePythonScript(PythonScriptRequest request) {
        ScriptInfo script = this.getById(request.getId());
        // 构建命令行参数
        List<String> command = new ArrayList<>();
        command.add("python"); // 或者是 python3，取决于你的环境
        command.add(fileService.getById(script.getFileId()).getPath()); // 脚本路径
        // 将 Map 中的参数添加到命令行参数中
        if (request.getParams() != null) {
            for (String value : request.getParams().values()) {
                command.add(value);
            }
        }
        // 执行脚本并传递参数
        try {
            PythonScriptExecutor.executeScript(command);
            return R.OK("Python script executed successfully!");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Boolean updateScript(Integer id,AddScriptDTO addScriptDTO) {
        ScriptInfo one = this.getById(id);
        ScriptInfo scriptInfo = new ScriptInfo();
        scriptInfo.setScriptName(addScriptDTO.getScriptName());
        scriptInfo.setScriptType(addScriptDTO.getScriptType());
        scriptInfo.setId(id);
        scriptInfo.setScriptStatic(0);
        scriptInfo.setCreateTime(one.getCreateTime());
        scriptInfo.setUpdateTime(LocalDateTime.now());
        scriptInfo.setScriptDesc(addScriptDTO.getScriptDesc());
        scriptInfo.setFunction(addScriptDTO.getFunction());
        scriptInfo.setLanguage(addScriptDTO.getLanguage());
        scriptInfo.setClassName(addScriptDTO.getClassName());
        scriptInfo.setInParameter(JSONUtil.toJsonStr(addScriptDTO.getInParameter()));
        scriptInfo.setOutParameter(JSONUtil.toJsonStr(addScriptDTO.getScriptName()));
        scriptInfo.setFileId(addScriptDTO.getFileId());
        if (this.updateById(scriptInfo)){
            return true;
        }else {
            return false;
        }
    }

    @Override
    public List<TaskScriptVO> taskGetScript() {
        List<ScriptInfo> list = this.list();
        List<TaskScriptVO> taskScriptVOS = new ArrayList<>();
        for (ScriptInfo scriptInfo : list) {
            TaskScriptVO taskScriptVO = new TaskScriptVO();
            taskScriptVO.setId(scriptInfo.getId());
            taskScriptVO.setScriptName(scriptInfo.getScriptName());
            taskScriptVOS.add(taskScriptVO);
        }
        return taskScriptVOS;
    }

    @Override
    public TaskScriptValueVO getValues(Integer id) {
        ScriptInfo one = this.getById(id);
        TaskScriptValueVO taskScriptValueVO = new TaskScriptValueVO();
        taskScriptValueVO.setScriptName(one.getScriptName());
        try {
            taskScriptValueVO.setScriptInValue(new ObjectMapper().readTree(one.getInParameter()));
            taskScriptValueVO.setScriptOutValue(new ObjectMapper().readTree(one.getOutParameter()));
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return taskScriptValueVO;
    }

    @Override
    public R uploadPythonScript(MultipartFile file) {
        if (file.isEmpty()) {
            return R.FAIL("上传的文件为空，请选择文件后再次上传。");
        }
        // 检查文件扩展名是否为 .py
        if (!file.getOriginalFilename().endsWith(".py")) {
            return R.FAIL("只允许上传 Python 脚本文件（.py）");
        }
        try {
            // 创建保存目录（如果不存在）
            File uploadDir = new File(UPLOAD_DIR);
            if (!uploadDir.exists()) {
                uploadDir.mkdirs();
            }
            // 保存文件到指定目录
            Path filePath = Paths.get(UPLOAD_DIR, file.getOriginalFilename());
            if (!Files.exists(filePath)) {
                Files.copy(file.getInputStream(), filePath);
            }
            LambdaQueryWrapper<FileBean> fileWrapper = new LambdaQueryWrapper<>();
            fileWrapper.eq(FileBean::getTypeName,"脚本管理")
                    .eq(FileBean::getPath,filePath.toString());
            FileBean one = fileService.getOne(fileWrapper);
            if (ObjectUtils.isEmpty(one)) {
                FileBean fileBean = new FileBean();
                fileBean.setPath(filePath.toString());
                fileBean.setTypeName("脚本管理");
                fileService.save(fileBean);
                return R.OK(fileBean.getId());
            }else {
                return R.OK(one.getId());
            }
        } catch (IOException e) {
            e.printStackTrace();
            return R.FAIL("文件上传失败：" + e.getMessage());
        }
    }

}
